﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;


namespace Von.Library
{
    /// <summary>
    ///  This class implements the ICE encryption algorithm.
    ///  Written by Matthew Kwan - December 1996
    ///  
    /// JAVA->C# 杜建平 2012/10/30
    /// </summary>
    public class IceKey
    {

        private int size;
        private int rounds;
        private List<int[]> keySchedule;

        private List<int[]> spBox;
        private bool spBoxInitialised = false;

        private List<int[]> sMod = null;
        private List<int[]> sXor = null;

        private int[] pBox = {
            0x00000001, 0x00000080, 0x00000400, 0x00002000,
            0x00080000, 0x00200000, 0x01000000, 0x40000000,
            0x00000008, 0x00000020, 0x00000100, 0x00004000,
            0x00010000, 0x00800000, 0x04000000, 0x20000000,
            0x00000004, 0x00000010, 0x00000200, 0x00008000,
            0x00020000, 0x00400000, 0x08000000, 0x10000000,
            0x00000002, 0x00000040, 0x00000800, 0x00001000,
            0x00040000, 0x00100000, 0x02000000, unchecked((int)0x80000000)};

        private int[] keyrot = {
                        0, 1, 2, 3, 2, 1, 3, 0,
                        1, 3, 2, 0, 3, 1, 0, 2};

        // 8-bit Galois Field multiplication of a by b, modulo m.
        // Just like arithmetic multiplication, except that
        // additions and subtractions are replaced by XOR.
        private int gf_mult(int a, int b, int m)
        {
            int res = 0;

            while (b != 0)
            {
                if ((b & 1) != 0)
                    res ^= a;

                a = a << 1;
                b = (int)(unchecked((uint)b) >> 1);

                if (a >= 256)
                    a ^= m;
            }

            return (res);
        }

        // 8-bit Galois Field exponentiation.
        // Raise the base to the power of 7, modulo m.
        private int gf_exp7(int b, int m)
        {
            int x;

            if (b == 0)
                return (0);

            x = gf_mult(b, b, m);
            x = gf_mult(b, x, m);
            x = gf_mult(x, x, m);
            return (gf_mult(b, x, m));
        }

        // Carry out the ICE 32-bit permutation.
        private int perm32(int x)
        {
            int res = 0;
            int i = 0;

            while (x != 0)
            {
                if ((x & 1) != 0)
                    res |= pBox[i];
                i++;
                //x = (int)(unchecked((uint)x) >> 1);
                x = UnsignedRightShift(x, 1);
            }

            return (res);
        }

        // Initialise the substitution/permutation boxes.
        private void spBoxInit()
        {
            int i;

            // spBox = new int[4, 1024];
            spBox = new List<int[]>();
            for (int index = 0; index < 4; index++)
            {
                spBox.Add(new int[1024]);
            }

            for (i = 0; i < 1024; i++)
            {
                int col = (UnsignedRightShift(i, 1)) & 0xff;
                int row = (i & 0x1) | UnsignedRightShift((i & 0x200), 8);
                int x;

                x = gf_exp7(col ^ sXor[0][row], sMod[0][row]) << 24;
                spBox[0][i] = perm32(x);

                x = gf_exp7(col ^ sXor[1][row], sMod[1][row]) << 16;
                spBox[1][i] = perm32(x);

                x = gf_exp7(col ^ sXor[2][row], sMod[2][row]) << 8;
                spBox[2][i] = perm32(x);

                x = gf_exp7(col ^ sXor[3][row], sMod[3][row]);
                spBox[3][i] = perm32(x);
            }
        }

        // Create a new ICE key with the specified level.
        public IceKey(int level)
        {

            sMod = new List<int[]>();
            sMod.Add(new int[] { 333, 313, 505, 369 });
            sMod.Add(new int[] { 379, 375, 319, 391 });
            sMod.Add(new int[] { 361, 445, 451, 397 });
            sMod.Add(new int[] { 397, 425, 395, 505 });

            sXor = new List<int[]>();
            sXor.Add(new int[] { 0x83, 0x85, 0x9b, 0xcd });
            sXor.Add(new int[] { 0xcc, 0xa7, 0xad, 0x41 });
            sXor.Add(new int[] { 0x4b, 0x2e, 0xd4, 0x33 });
            sXor.Add(new int[] { 0xea, 0xcb, 0x2e, 0x04 });

            if (!spBoxInitialised)
            {
                spBoxInit();
                spBoxInitialised = true;
            }

            if (level < 1)
            {
                size = 1;
                rounds = 8;
            }
            else
            {
                size = level;
                rounds = level * 16;
            }

            //	    keySchedule = new int[rounds,3];
            keySchedule = new List<int[]>();
            for (int i = 0; i < rounds; i++)
            {
                keySchedule.Add(new int[3]);
            }
        }

        // Set 8 rounds [n, n+7] of the key schedule of an ICE key.
        private void scheduleBuild(int[] kb, int n, int krot_idx)
        {
            int i;

            for (i = 0; i < 8; i++)
            {
                int j;
                int kr = keyrot[krot_idx + i];
                int[] subkey = keySchedule[n + i];

                for (j = 0; j < 3; j++)
                    keySchedule[n + i][j] = 0;

                for (j = 0; j < 15; j++)
                {
                    int k;
                    int curr_sk = j % 3;

                    for (k = 0; k < 4; k++)
                    {
                        int curr_kb = kb[(kr + k) & 3];
                        int bit = curr_kb & 1;

                        subkey[curr_sk] = (subkey[curr_sk] << 1) | bit;
                        kb[(kr + k) & 3] = UnsignedRightShift(curr_kb, 1) | ((bit ^ 1) << 15);
                    }
                }
            }
        }

        // Set the key schedule of an ICE key.
        public void set(byte[] key)
        {
            int i;
            int[] kb = new int[4];

            if (rounds == 8)
            {
                for (i = 0; i < 4; i++)
                    kb[3 - i] = ((key[i * 2] & 0xff) << 8)
                                | (key[i * 2 + 1] & 0xff);

                scheduleBuild(kb, 0, 0);
                return;
            }

            for (i = 0; i < size; i++)
            {
                int j;

                for (j = 0; j < 4; j++)
                    kb[3 - j] = ((key[i * 8 + j * 2] & 0xff) << 8)
                                | (key[i * 8 + j * 2 + 1] & 0xff);

                scheduleBuild(kb, i * 8, 0);
                scheduleBuild(kb, rounds - 8 - i * 8, 8);
            }
        }

        // Clear the key schedule to prevent memory snooping.
        public void clear()
        {
            int i, j;

            for (i = 0; i < rounds; i++)
                for (j = 0; j < 3; j++)
                    keySchedule[i][j] = 0;
        }

        // The single round ICE f function.
        private int roundFunc(int p, int[] subkey)
        {
            int tl, tr;
            int al, ar;

            tl = (UnsignedRightShift(p, 16) & 0x3ff) | ((UnsignedRightShift(p, 14) | (p << 18)) & 0xffc00);
            tr = (p & 0x3ff) | ((p << 2) & 0xffc00);

            // al = (tr & subkey[2]) | (tl & ~subkey[2]);
            // ar = (tl & subkey[2]) | (tr & ~subkey[2]);
            al = subkey[2] & (tl ^ tr);
            ar = al ^ tr;
            al ^= tl;

            al ^= subkey[0];
            ar ^= subkey[1];

            return (spBox[0][UnsignedRightShift(al, 10)] | spBox[1][al & 0x3ff]
                    | spBox[2][UnsignedRightShift(ar, 10)] | spBox[3][ar & 0x3ff]);
        }

        // Encrypt a block of 8 bytes of data.
        public void encrypt(byte[] plaintext, byte[] ciphertext)
        {
            int i;
            int l = 0, r = 0;

            for (i = 0; i < 4; i++)
            {
                l |= (plaintext[i] & 0xff) << (24 - i * 8);
                r |= (plaintext[i + 4] & 0xff) << (24 - i * 8);
            }

            for (i = 0; i < rounds; i += 2)
            {
                l ^= roundFunc(r, keySchedule[i]);
                r ^= roundFunc(l, keySchedule[i + 1]);
            }

            for (i = 0; i < 4; i++)
            {
                ciphertext[3 - i] = (byte)(r & 0xff);
                ciphertext[7 - i] = (byte)(l & 0xff);

                r = UnsignedRightShift(r, 8);
                l = UnsignedRightShift(l, 8);
                //		r >>>= 8;
                //		l >>>= 8;
            }
        }

        // Decrypt a block of 8 bytes of data.
        public void decrypt(byte[] ciphertext, byte[] plaintext)
        {
            int i;
            int l = 0, r = 0;

            for (i = 0; i < 4; i++)
            {
                l |= (ciphertext[i] & 0xff) << (24 - i * 8);
                r |= (ciphertext[i + 4] & 0xff) << (24 - i * 8);
            }

            for (i = rounds - 1; i > 0; i -= 2)
            {
                l ^= roundFunc(r, keySchedule[i]);
                r ^= roundFunc(l, keySchedule[i - 1]);
            }

            for (i = 0; i < 4; i++)
            {
                plaintext[3 - i] = (byte)(r & 0xff);
                plaintext[7 - i] = (byte)(l & 0xff);

                r = UnsignedRightShift(r, 8);
                l = UnsignedRightShift(l, 8);
                //		r >>>= 8;
                //		l >>>= 8;
            }
        }

        // Return the key size, in bytes.
        public int keySize()
        {
            return (size * 8);
        }

        // Return the block size, in bytes.
        public int blockSize()
        {
            return (8);
        }

        /// <summary>
        /// 无符号右移
        /// </summary>
        /// <param name="value">原始值</param>
        /// <param name="digit">位数</param>
        /// <returns></returns>
        public int UnsignedRightShift(int value, int digit)
        {
            return (int)(unchecked((uint)value) >> digit);
        }
    }
    /// <summary>
    /// Jamesvon 发明的XOR迭次加密算法，速度快，重复率低，适用于短词加密
    /// byte[]加密结果比原始byte[]要多一个字节，因此在进入声明时要注意
    /// </summary>
    public class VonCryption
    {
        private byte[] KEY_DEFAULT = {
            0x09, 0xd0, 0xc4, 0x79, 0x28, 0xc8, 0xff, 0xe0, 0x84, 0xaa, 0x6c, 0x39, 0x9d, 0xad, 0x72, 0x87,
            0x7d, 0xff, 0x9b, 0xe3, 0xd4, 0x26, 0x83, 0x61, 0xc9, 0x6d, 0xa1, 0xd4, 0x79, 0x74, 0xcc, 0x93,
            0x85, 0xd0, 0x58, 0x2e, 0x2a, 0x4b, 0x57, 0x05, 0x1c, 0xa1, 0x6a, 0x62, 0xc3, 0xbd, 0x27, 0x9d,
            0x0f, 0x1f, 0x25, 0xe5, 0x51, 0x60, 0x37, 0x2f, 0xc6, 0x95, 0xc1, 0xfb, 0x4d, 0x7f, 0xf1, 0xe4,
            0xae, 0x5f, 0x6b, 0xf4, 0x0d, 0x72, 0xee, 0x46, 0xff, 0x23, 0xde, 0x8a, 0xb1, 0xcf, 0x8e, 0x83,
            0xf1, 0x49, 0x02, 0xe2, 0x3e, 0x98, 0x1e, 0x42, 0x8b, 0xf5, 0x3e, 0xb6, 0x7f, 0x4b, 0xf8, 0xac,
            0x83, 0x63, 0x1f, 0x83, 0x25, 0x97, 0x02, 0x05, 0x76, 0xaf, 0xe7, 0x84, 0x3a, 0x79, 0x31, 0xd4,
            0x4f, 0x84, 0x64, 0x50, 0x5c, 0x64, 0xc3, 0xf6, 0x21, 0x0a, 0x5f, 0x18, 0xc6, 0x98, 0x6a, 0x26,
            0x28, 0xf4, 0xe8, 0x26, 0x3a, 0x60, 0xa8, 0x1c, 0xd3, 0x40, 0xa6, 0x64, 0x7e, 0xa8, 0x20, 0xc4,
            0x52, 0x66, 0x87, 0xc5, 0x7e, 0xdd, 0xd1, 0x2b, 0x32, 0xa1, 0x1d, 0x1d, 0x9c, 0x9e, 0xf0, 0x86,
            0x80, 0xf6, 0xe8, 0x31, 0xab, 0x6f, 0x04, 0xad, 0x56, 0xfb, 0x9b, 0x53, 0x8b, 0x2e, 0x09, 0x5c,
            0xb6, 0x85, 0x56, 0xae, 0xd2, 0x25, 0x0b, 0x0d, 0x29, 0x4a, 0x77, 0x21, 0xe2, 0x1f, 0xb2, 0x53,
            0xae, 0x13, 0x67, 0x49, 0xe8, 0x2a, 0xae, 0x86, 0x93, 0x36, 0x51, 0x04, 0x99, 0x40, 0x4a, 0x66,
            0x78, 0xa7, 0x84, 0xdc, 0xb6, 0x9b, 0xa8, 0x4b, 0x04, 0x04, 0x67, 0x93, 0x23, 0xdb, 0x5c, 0x1e,
            0x46, 0xca, 0xe1, 0xd6, 0x2f, 0xe2, 0x81, 0x34, 0x5a, 0x22, 0x39, 0x42, 0x18, 0x63, 0xcd, 0x5b,
            0xc1, 0x90, 0xc6, 0xe3, 0x07, 0xdf, 0xb8, 0x46, 0x6e, 0xb8, 0x88, 0x16, 0x2d, 0x0d, 0xcc, 0x4a};
        public VonCryption(string key)
        {
            byte[] b = Encoding.UTF8.GetBytes(key);
            for (int i = 0; i < 256; i++)
            {
                KEY_DEFAULT[i] = (byte)(KEY_DEFAULT[i] ^ b[i % b.Length]);
            }
        }
        public void Encrypt(byte[] InData, byte[] OutData)
        {
            byte idx = 0;
            foreach (byte b in InData) idx += b;
            OutData[0] = idx;
            for (int i = 0; i < InData.Length; i++)
            {
                OutData[i + 1] = (byte)(InData[i] ^ KEY_DEFAULT[(idx + i) % 256]);
                OutData[i + 1] = (byte)(OutData[i + 1] ^ KEY_DEFAULT[(idx + i + 1) % 256]);
            }
        }
        public void Decrypt(byte[] InData, byte[] OutData)
        {
            byte idx = InData[0];
            for (int i = 1; i < InData.Length; i++)
            {
                OutData[i - 1] = (byte)(InData[i] ^ KEY_DEFAULT[(idx + i) % 256]);
                OutData[i - 1] = (byte)(OutData[i - 1] ^ KEY_DEFAULT[(idx + i - 1) % 256]);
            }
        }
        public string EncryptString(string str)
        {
            byte[] InData = Encoding.UTF8.GetBytes(str);
            byte[] OutData = new byte[InData.Length + 1];
            Encrypt(InData, OutData);
            return Convert.ToBase64String(OutData);
        }
        public string DecryptString(string str)
        {
            byte[] InData = Convert.FromBase64String(str);
            byte[] OutData = new byte[InData.Length - 1];
            Decrypt(InData, OutData);
            return Encoding.UTF8.GetString(OutData);
        }
    }
    public enum EHashValueKind { HEX, B64, V64 }
    /// <summary>
    /// 对传入的字符串进行Hash运算，返回通过Hash算法加密过的字串。
    /// 方法：此类提供MD5，SHA1，SHA256，SHA512等四种算法，加密字串的长度依次增大。
    /// </summary>
    public class HashEncrypt
    {
        // 返回数据方式 0：以Hex方式返回，1：以B64码返回，2：以内部64码返回
        private EHashValueKind valueKind = EHashValueKind.B64;

        public HashEncrypt(EHashValueKind ValueKind = EHashValueKind.B64)
        {
            this.valueKind = ValueKind;
        }

        private string getstrIN(string strIN)
        {
            //string strIN = strIN;
            if (strIN.Length == 0)
            {
                strIN = "~NULL~";
            }
            return strIN;
        }

        public string MD5Encrypt(string strIN)
        {
            //string strIN = getstrIN(strIN);
            byte[] tmpByte;
            MD5 md5 = new MD5CryptoServiceProvider();
            tmpByte = md5.ComputeHash(GetKeyByteArray(getstrIN(strIN)));
            md5.Clear();
            return GetStringValue(tmpByte);
        }

        public string SHA1Encrypt(string strIN)
        {
            //string strIN = getstrIN(strIN);
            byte[] tmpByte;
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            tmpByte = sha1.ComputeHash(GetKeyByteArray(strIN));
            sha1.Clear();
            return GetStringValue(tmpByte);
        }

        public string SHA256Encrypt(string strIN)
        {
            //string strIN = getstrIN(strIN);
            byte[] tmpByte;
            SHA256 sha256 = new SHA256Managed();
            tmpByte = sha256.ComputeHash(GetKeyByteArray(strIN));
            sha256.Clear();
            return GetStringValue(tmpByte);
        }

        public string SHA512Encrypt(string strIN)
        {
            //string strIN = getstrIN(strIN);
            byte[] tmpByte;
            SHA512 sha512 = new SHA512Managed();
            tmpByte = sha512.ComputeHash(GetKeyByteArray(strIN));
            sha512.Clear();
            return GetStringValue(tmpByte);
        }

        /// <summary>
        /// 使用DES加密（Added by niehl 2005-4-6）
        /// </summary>
        /// <param name="originalValue">待加密的字符串</param>
        /// <param name="key">密钥(最大长度8)</param>
        /// <param name="IV">初始化向量(最大长度8)</param>
        /// <returns>加密后的字符串</returns>
        public string DESEncrypt(string originalValue, string key, string IV)
        {
            //将key和IV处理成8个字符
            key += "12345678";
            IV += "12345678";
            key = key.Substring(0, 8);
            IV = IV.Substring(0, 8);

            SymmetricAlgorithm sa;
            ICryptoTransform ct;
            MemoryStream ms;
            CryptoStream cs;
            byte[] byt;

            sa = new DESCryptoServiceProvider();
            sa.Key = Encoding.UTF8.GetBytes(key);
            sa.IV = Encoding.UTF8.GetBytes(IV);
            ct = sa.CreateEncryptor();

            byt = Encoding.UTF8.GetBytes(originalValue);

            ms = new MemoryStream();
            cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
            cs.Write(byt, 0, byt.Length);
            cs.FlushFinalBlock();
            cs.Close();

            return Convert.ToBase64String(ms.ToArray());
        }

        public string DESEncrypt(string originalValue, string key)
        {
            return DESEncrypt(originalValue, key, key);
        }

        /// <summary>
        /// 使用DES解密（Added by niehl 2005-4-6）
        /// </summary>
        /// <param name="encryptedValue">待解密的字符串</param>
        /// <param name="key">密钥(最大长度8)</param>
        /// <param name="IV">m初始化向量(最大长度8)</param>
        /// <returns>解密后的字符串</returns>
        public string DESDecrypt(string encryptedValue, string key, string IV)
        {
            //将key和IV处理成8个字符
            key += "12345678";
            IV += "12345678";
            key = key.Substring(0, 8);
            IV = IV.Substring(0, 8);

            SymmetricAlgorithm sa;
            ICryptoTransform ct;
            MemoryStream ms;
            CryptoStream cs;
            byte[] byt;

            sa = new DESCryptoServiceProvider();
            sa.Key = Encoding.UTF8.GetBytes(key);
            sa.IV = Encoding.UTF8.GetBytes(IV);
            ct = sa.CreateDecryptor();

            byt = Convert.FromBase64String(encryptedValue);

            ms = new MemoryStream();
            cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
            cs.Write(byt, 0, byt.Length);
            cs.FlushFinalBlock();
            cs.Close();

            return Encoding.UTF8.GetString(ms.ToArray());
        }

        public string DESDecrypt(string encryptedValue, string key)
        {
            return DESDecrypt(encryptedValue, key, key);
        }

        private string GetStringValue(byte[] Byte)
        {
            string tmpString = "";
            int iCounter;

            switch (this.valueKind)
            {
                case EHashValueKind.HEX:
                    for (iCounter = 0; iCounter < Byte.Length; iCounter++) tmpString += Byte[iCounter].ToString("x"); break;
                case EHashValueKind.B64:
                    tmpString = Convert.ToBase64String(Byte); break;
                case EHashValueKind.V64:
                    tmpString = Functions.BytesToStr(Byte); break;
            }
            return tmpString;
        }

        private byte[] GetKeyByteArray(string strKey)
        {

            ASCIIEncoding Asc = new ASCIIEncoding();

            int tmpStrLen = strKey.Length;
            byte[] tmpByte = new byte[tmpStrLen - 1];

            tmpByte = Asc.GetBytes(strKey);

            return tmpByte;

        }

    }
}